package com.whfc.emp.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.whfc.common.enums.Gender;
import com.whfc.common.exception.BizException;
import com.whfc.common.result.PageData;
import com.whfc.common.util.CollectionUtil;
import com.whfc.common.util.DateUtil;
import com.whfc.common.util.MathUtil;
import com.whfc.common.util.PageUtil;
import com.whfc.emp.dao.*;
import com.whfc.emp.dto.*;
import com.whfc.emp.entity.AppEmpData;
import com.whfc.emp.enums.AttendState;
import com.whfc.emp.enums.EmpAgeType;
import com.whfc.emp.enums.EnterType;
import com.whfc.emp.param.EmpAttendPlan;
import com.whfc.emp.service.AppEmpDataAnaService;
import com.whfc.fuum.dto.AppCorpDTO;
import com.whfc.fuum.service.AppCorpService;
import com.whfc.fuum.service.SysDeptService;
import com.whfc.fuum.service.SysDictService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClasssName AppEmpDataAnaServiceImpl
 * @Description 数据分析
 * @Author hw
 * @Date 2020/12/29 11:42
 * @Version 1.0
 */
@DubboService(interfaceClass = AppEmpDataAnaService.class, version = "1.0.0", timeout = 30 * 1000)
public class AppEmpDataAnaServiceImpl implements AppEmpDataAnaService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @DubboReference(interfaceClass = SysDeptService.class, version = "1.0.0")
    private SysDeptService commonDeptService;

    @DubboReference(interfaceClass = SysDictService.class, version = "1.0.0")
    private SysDictService sysDictService;

    @DubboReference(interfaceClass = AppCorpService.class, version = "1.0.0")
    private AppCorpService appCorpService;

    @Autowired
    private AppEmpDayMapper appEmpDayMapper;

    @Autowired
    private AppEmpMapper appEmpMapper;

    @Autowired
    private AppEmpDataMapper appEmpDataMapper;

    @Autowired
    private AppEmpGroupMapper appEmpGroupMapper;

    @Autowired
    private AppEmpEnterRecordMapper empEnterRecordMapper;

    @Autowired
    private AppEmpDeptDayMapper appEmpDeptDayMapper;

    @Override
    public AppEmpDataDTO getEmpData(Integer deptId) {
        logger.info("人员分析-获取人员分析数据,deptId：{}", deptId);
        Date now = new Date();
        Date today = DateUtil.getDateEnd(now);
        Date startDate = DateUtil.getDateBegin(DateUtil.addDays(today, -6));

        //人数统计
        AppEmpAnaNumDTO enterEmp = appEmpMapper.selectEmpNumByDeptId(deptId);
        enterEmp.setWorkerNum(enterEmp.getEmpTotal() - enterEmp.getManagerNum());

        //出勤统计
        AppEmpAnaNumDTO todayAttendEmp = appEmpDataMapper.selectAttendNum(deptId);
        //获取当日计划出勤人数
        // 默认为总人数
        int planAttendNum = enterEmp.getEmpTotal();
        EmpAttendPlan empAttendPlan = appEmpDeptDayMapper.selectByDeptIdAndDate(deptId, now);
        if (empAttendPlan != null) {
            planAttendNum = empAttendPlan.getPlanAttendNum();
        }
        todayAttendEmp.setPlanAttendNum(planAttendNum);

        //每日统计
        List<EmpDataDTO> attendList = appEmpDayMapper.selectEmpNumTotalPerDay(deptId, startDate, today);
        List<AppEmpAnaWeekDataDTO> enterList = empEnterRecordMapper.selectDayStatStat(deptId, startDate, today);
        Map<Date, EmpDataDTO> attendMap = CollectionUtil.list2Map(attendList, EmpDataDTO::getDate);
        Map<Date, AppEmpAnaWeekDataDTO> enterMap = CollectionUtil.list2Map(enterList, AppEmpAnaWeekDataDTO::getDate);

        List<Date> dateList = DateUtil.getDayList(startDate, today);
        List<AppEmpAnaWeekDataDTO> weekDataList = new ArrayList<>(dateList.size());
        for (Date date : dateList) {
            Integer attendNum = attendMap.containsKey(date) ? attendMap.get(date).getAttendNum() : 0;
            Integer enterNum = enterMap.containsKey(date) ? enterMap.get(date).getEnterNum() : 0;
            Integer outerNum = enterMap.containsKey(date) ? enterMap.get(date).getOuterNum() : 0;
            AppEmpAnaWeekDataDTO record = new AppEmpAnaWeekDataDTO(date, enterNum, outerNum, attendNum);
            weekDataList.add(record);
        }

        AppEmpDataDTO data = new AppEmpDataDTO();
        data.setTodayAttendEmp(todayAttendEmp);
        data.setWeekDataList(weekDataList);
        data.setEnterEmp(enterEmp);
        statisticalAge(deptId, data);
        return data;
    }

    @Override
    public AppEmpSpotDataDTO getSpotEmpData(Integer deptId) {
        AppEmpSpotDataDTO appEmpSpotDataDTO = new AppEmpSpotDataDTO();
        AppEmpAnaNumDTO enterEmp = appEmpMapper.selectEmpNumByDeptId(deptId);
        // 在职总人数
        appEmpSpotDataDTO.setEnterEmpCount(enterEmp.getEmpTotal());
        // 获取工人出勤信息
        Date now = new Date();
        AppEmpAnaNumDTO todayAttendEmp = appEmpDayMapper.selectAttendNum(deptId,now);
        // 工人出勤率 工人出勤人数除以出勤工人总数
        appEmpSpotDataDTO.setWorkerRate(MathUtil.divide(todayAttendEmp.getAttendNum(), todayAttendEmp.getWorkerNum(), 4));

        //人员班组分类统计
        List<AppEmpAttendGroupDTO> list = appEmpMapper.selectGroupNumByDeptId(deptId);
        // 班组出勤统计
        List<AppEmpAttendGroupDTO> groupAttendList =appEmpDayMapper.selectGroupAttendNum(deptId,now);
        Map<Integer, Integer> groupAttendListMap = groupAttendList.stream().collect(Collectors.toMap(AppEmpAttendGroupDTO::getId, AppEmpAttendGroupDTO::getAttNum));
        for (AppEmpAttendGroupDTO appEmpAttendGroupDTO : list) {
            Integer attNum = groupAttendListMap.get(appEmpAttendGroupDTO.getId());
            appEmpAttendGroupDTO.setAttNum(attNum==null?0:attNum);
        }
        appEmpSpotDataDTO.setGroupList(list);
        List<AppEmpDTO> managerEmpList = appEmpMapper.selectManagerEmpByDeptId(deptId);
        appEmpSpotDataDTO.setManagerEmpList(managerEmpList);
        long count = managerEmpList.stream().filter(s -> "1".equals(s.getAttendState() + "")).count();
        if (count==0L) {
            appEmpSpotDataDTO.setManagerRate(0.00);
        }else if (count ==1L){
            appEmpSpotDataDTO.setManagerRate(0.50);
        }else {
            appEmpSpotDataDTO.setManagerRate(1.00);
        }
        return appEmpSpotDataDTO;
    }

    @Override
    public PageData<AppAnaEmpDTO> getRecentAttendEmp(Integer deptId) {
        logger.info("人员分析-获取最近出勤人员,deptId：{}", deptId);
        PageHelper.startPage(1, 20);
        List<AppAnaEmpDTO> list = appEmpDayMapper.selectRecentAttendEmp(deptId);
        PageHelper.clearPage();

        return PageUtil.pageData(PageInfo.of(list));
    }

    @Override
    public PageData<AppAnaEmpDTO> getRecentEnterEmp(Integer deptId) {
        logger.info("人员分析-获取最近进场人员,deptId：{}", deptId);
        PageHelper.startPage(1, 20);
        List<AppAnaEmpDTO> list = appEmpMapper.selectRecentEnterEmp(deptId);
        PageHelper.clearPage();
        return PageUtil.pageData(PageInfo.of(list));
    }

    @Override
    public AppEmpStatisticsDTO getGroupEmp(Integer deptId) throws BizException {
        logger.info("人员分析-班组统计,deptId：{}", deptId);
        //总人数
        Integer empTotal = appEmpMapper.countByDeptId(deptId);
        //人员分类统计
        List<AppEmpAttendGroupDTO> list = appEmpMapper.selectGroupNumByDeptId(deptId);
        for (AppEmpAttendGroupDTO groupDTO : list) {
            Double rate = MathUtil.divide(groupDTO.getNum(), empTotal, 4);
            groupDTO.setRate(rate);
        }
        return new AppEmpStatisticsDTO(empTotal, list);
    }

    @Override
    public AppEmpStatisticsDTO getCorpEmp(Integer deptId) throws BizException {
        logger.info("人员分析-合作单位统计,deptId：{}", deptId);

        //总人数
        Integer empTotal = appEmpMapper.countByDeptId(deptId);

        //合作单位
        List<AppCorpDTO> appCorpDTOS = appCorpService.list(deptId);
        Map<Integer, String> corpMap = new HashMap<>(appCorpDTOS.size());
        for (AppCorpDTO corp : appCorpDTOS) {
            corpMap.put(corp.getCorpId(), corp.getCorpName());
        }

        //人员分类统计
        List<AppEmpAttendGroupDTO> list = appEmpMapper.selectCorpNumByDeptId(deptId);
        for (AppEmpAttendGroupDTO groupDTO : list) {
            if (corpMap.containsKey(groupDTO.getId())) {
                groupDTO.setName(corpMap.get(groupDTO.getId()));
            }
            Double rate = MathUtil.divide(groupDTO.getNum(), empTotal, 4);
            groupDTO.setRate(rate);
        }
        return new AppEmpStatisticsDTO(empTotal, list);
    }

    @Override
    public AppEmpStatisticsDTO getWorkEmp(Integer deptId) throws BizException {
        logger.info("人员分析-工种统计,deptId：{}", deptId);
        //总人数
        Integer empTotal = appEmpMapper.countByDeptId(deptId);

        //人员分类统计
        List<AppEmpAttendGroupDTO> list = appEmpMapper.selectWorkNumByDeptId(deptId);
        for (AppEmpAttendGroupDTO groupDTO : list) {
            groupDTO.setRate(MathUtil.divide(groupDTO.getNum(), empTotal, 4));
        }
        return new AppEmpStatisticsDTO(empTotal, list);
    }

    @Override
    public List<AppEmpAttendGroupDTO> getWordDayAttendData(Integer deptId, Date date) throws BizException {
        return appEmpGroupMapper.selectGroupAttendNum(deptId, date);
    }


    @Override
    public AppEmpLogDTO getEmpLog(Integer deptId, Date date) throws BizException {
        AppEmpLogDTO appEmpLogDTO = appEmpDayMapper.selectEmpLog(deptId, date);
        List<AppEmpDTO> list = empEnterRecordMapper.selectEmpLog(deptId, date);
        List<AppEmpDTO> enterList = new ArrayList<>();
        List<AppEmpDTO> outerList = new ArrayList<>();
        list.forEach(appEmpDTO -> {
            if (EnterType.enter.getValue().equals(appEmpDTO.getType())) {
                enterList.add(appEmpDTO);
            } else {
                outerList.add(appEmpDTO);
            }
        });
        appEmpLogDTO.setEnterList(enterList);
        appEmpLogDTO.setOuterList(outerList);
        return appEmpLogDTO;
    }

    /**
     * 统计人员年龄
     *
     * @param deptId
     * @return
     */
    private void statisticalAge(Integer deptId, AppEmpDataDTO data) {

        //人员年龄列表
        List<EmpAge> ageList = appEmpMapper.selectBirthdayByDeptId(deptId);

        //按按年龄分类
        Map<EmpAgeType, List<EmpAge>> ageTypeMap = CollectionUtil.groupBy(ageList, x -> EmpAgeType.parseByAge(x.getAge()));
        EmpAgeType[] ageTypes = EmpAgeType.values();
        List<AppEmpAgeDTO> retList = new ArrayList<>(ageTypes.length);
        for (EmpAgeType ageType : ageTypes) {
            AppEmpAgeDTO ageDTO = new AppEmpAgeDTO(ageType.getType());
            retList.add(ageDTO);
            if (ageTypeMap.containsKey(ageType)) {
                List<EmpAge> typeAgeList = ageTypeMap.get(ageType);
                Integer ageNum = typeAgeList.size();
                int manNum = 0;
                int womanNum = 0;
                int otherNum = 0;
                for (EmpAge age : typeAgeList) {
                    if (Gender.man.getValue().equals(age.getGender())) {
                        manNum++;
                    } else if (Gender.woman.getValue().equals(age.getGender())) {
                        womanNum++;
                    } else {
                        otherNum++;
                    }
                }
                double manPercent = MathUtil.divide(manNum * 100, ageNum, 2);
                double womanPercent = MathUtil.divide(womanNum * 100, ageNum, 2);
                double otherPercent = MathUtil.divide(otherNum * 100, ageNum, 2);
                ageDTO.setAgeNum(ageNum);
                ageDTO.setManNum(manNum);
                ageDTO.setWomanNum(womanNum);
                ageDTO.setOtherNum(otherNum);
                ageDTO.setManPercent(manPercent);
                ageDTO.setWomanPercent(womanPercent);
                ageDTO.setOtherPercent(otherPercent);
            }
        }

        //平均年龄
        OptionalDouble optionalAge = ageList.stream().filter(x -> x.getAge() != null).mapToInt(EmpAge::getAge).average();
        double avgAge = optionalAge.isPresent() ? optionalAge.getAsDouble() : 0;
        data.setAverage(MathUtil.doule2int(avgAge));
        data.setEmpAge(retList);
    }

    public static void main(String[] args) {
        Date now = new Date();
        Date today = DateUtil.getDateEnd(now);
        Date startDate = DateUtil.addDays(today, -6);
        System.out.println(startDate);
    }
}
